/*
 * @Description:
 * @Version: 2.0
 * @Autor: wiz
 * @Date: 2024-07-12 22:15:51
 * @LastEditors: zss
 * @LastEditTime: 2024-11-12 17:06:39
 */
import { ifs, ts, Tsrv } from '@/services';
import { N_cFlowchart, N_oContextMenu } from '@/types';
import { DataUri } from '@antv/x6';
import {
  cellContentMenuItem,
  edgeContentMenuItem,
  nodeContentMenuItem
} from './config';
import { N_girdFlowchart } from './types';

type I_graphEventParams =
  | N_cFlowchart.I_eventParams
  | N_cFlowchart.I_edgeConnectParams
  | N_cFlowchart.I_edgeEventParams
  | N_cFlowchart.I_nodeEventParams;
class T_cmd {
  // 主组件箱
  private compBox: ifs.I_compBox;

  // 主组件ID
  private compID: string;

  // 主组件实例
  private self: N_girdFlowchart.girdFlowchart;

  private currEventParams: N_cFlowchart.I_eventParams = null;

  private _graphEditorState: N_cFlowchart.I_editorState = 'none';

  private currentNode: N_cFlowchart.x6Node = null;

  private currentRow: any = null;

  private currentRowData: any = null;

  // constructor() {
  //   //
  // }

  public regGraphEvents: Map<
    N_cFlowchart.EVENTS,
    (e: I_graphEventParams) => void
  > = new Map();

  public regToolbarEvents: Map<
    string,
    N_cFlowchart.I_toolbarEventFun
  > = new Map();

  public regShortcuts: Map<string, N_cFlowchart.I_shortcutsFun> = new Map();

  // 主组件created里初始化
  public init(self: any, compBoxInfo: ifs.I_compBoxInfo) {
    this.self = self;
    this.compBox = compBoxInfo.TcompBox;
    this.compID = compBoxInfo.compID;
    this.regGraphEvents.set(
      N_cFlowchart.EVENTS.BLANK_CLICK,
      this.graphBlankClick
    );
    this.regGraphEvents.set(
      N_cFlowchart.EVENTS.NODE_CLICK,
      this.graphNodeClick
    );
    this.regGraphEvents.set(
      N_cFlowchart.EVENTS.NODE_DBLCLICK,
      this.graphNodeDbClick
    );
    this.regGraphEvents.set(
      N_cFlowchart.EVENTS.NODE_CONTEXTMENU,
      this.nodeContextMenu
    );
    this.regGraphEvents.set(
      N_cFlowchart.EVENTS.EDGE_CONTEXTMENU,
      this.edgeContextMenu
    );
    // 画布空白处  右键菜单
    this.regGraphEvents.set(
      N_cFlowchart.EVENTS.BLANK_CONTEXTMENU,
      this.blankContextMenu
    );
    // edge边的链接、取消事件 （修改）
    this.regGraphEvents.set(
      N_cFlowchart.EVENTS.EDGE_CONNECTED,
      this.edgeConnected
    );
    this.regGraphEvents.set(N_cFlowchart.EVENTS.RENDER_DONE, this.renderDone);
    // edge边的添加事件
    // this.regGraphEvents.set(N_cFlowchart.EVENTS.EDGE_ADDED, this.edgeAdded);
    // edge边的删除事件
    this.regGraphEvents.set(N_cFlowchart.EVENTS.EDGE_REMOVED, this.edgeRemoved);
    this.regGraphEvents.set(N_cFlowchart.EVENTS.NODE_REMOVED, this.nodeRemoved);
    // this.regGraphEvents.set(N_cFlowchart.EVENTS.NODE_ADDED, this.nodeAdded);
    // this.regToolbarEvents.set('before_save', this.toolbarBeforeSave);
    // this.regToolbarEvents.set('before_delete', this.toolbarBeforeDelete);
    // this.regToolbarEvents.set('before_new', this.toolbarBeforeNew);
    this.regToolbarEvents.set('before_refresh', this.toolbarBeforeRefresh);
    // 快捷键
    this.regShortcuts.set('atl+`', this.switchModel);
  }

  public switchModel: Function = (e: any) => {
    // 切换前检查————
    this.self.$emit('switch-model');
  };

  public set graphEditorState(state: N_cFlowchart.I_editorState) {
    this._graphEditorState = state;
  }

  public getTcmd(): T_cmd {
    return this;
  }

  public get graphEditorState(): N_cFlowchart.I_editorState {
    return this._graphEditorState;
  }

  // graph event
  graphBlankClick = (e: N_cFlowchart.I_eventParams) => {
    this.setCurrEventParams(e);
    this.self.cFlowchart.hideContextMenu();
  };

  graphNodeClick = (e: N_cFlowchart.I_eventParams) => {
    this.setCurrEventParams(e);
    this.self.cFlowchart.hideContextMenu();
    const node = e.node;
    this.currentNode = node;
    this.currentRow = this.self.localData.find(item => item?.id === node.id);
    const currentRowData = {
      config: this.self.tableCfg,
      ev: {}
    };
    currentRowData.ev['row'] = this.currentRow;
    // currentRowData.ev['column'] = this.self.oBaseGrid.grid.getColumnByField(field);
    this.currentRowData = currentRowData;
    this.handleNodeClick();
  };

  public handleNodeClick() {
    //
    if (!Tsrv.noValue(this.currentRow)) {
      this.self.oBaseGrid.setCurrentRow(this.currentRow);
    }
  }

  graphNodeDbClick = (e: N_cFlowchart.I_eventParams) => {
    if (!this.self.cFlowchart.isDenyEdit()) {
      this.self.oBaseGrid.showRowEditor(this.currentRowData.ev); // 显示行编辑器
    }
  };

  toolbarBeforeNew = (e: N_cFlowchart.cFlowchart): Promise<boolean> => {
    return new Promise((resolve, reject) => {
      resolve(true);
    });
  };

  // toolbar event
  toolbarBeforeSave = (e: N_cFlowchart.cFlowchart): Promise<boolean> => {
    return new Promise((resolve, reject) => {
      //
    });
  };

  toolbarBeforeDelete = (e: N_cFlowchart.cFlowchart): Promise<boolean> => {
    return new Promise((resolve, reject) => {
      this.self.$Modal.confirm({
        title: Tsrv.getI18nByValue('提示'),
        content: Tsrv.getI18nByValue('确定删除'),
        closable: true,
        onOk: () => {
          this.doDel().then(ok => {
            if (ok) {
              resolve(true);
            } else {
              resolve(false);
            }
          });
        },
        onCancel: () => {
          resolve(false);
        }
      });
    });
  };

  toolbarBeforeRefresh = (e: N_cFlowchart.cFlowchart): Promise<boolean> => {
    return new Promise((resolve, reject) => {
      this.self.oBaseGrid.commitEvent('refresh');
    });
  };

  renderDone = (e: any) => {
    // this.self.cFlowchart.layout();
    // this.self.cFlowchart.graph.zoomToFit({
    //   padding: 20,
    //   preserveAspectRatio: true
    // });
  };

  private doDel() {
    return new Promise<boolean>((resolve, reject) => {
      //
    });
  }

  private deleteNode() {
    const currentRow = Tsrv.utils.clone(this.currentRowData.ev?.row, true);
    this.self.$emit('on-row-change', 'delete', currentRow);
    const rowID = currentRow?.id;
    // const graphData = this.self.getGraphData();
    // const nodes = graphData?.nodes;
    // const tableEditor = this.self.oBaseGrid.GT_editor;
    // if (rowID && this.self.localData.length > 0) {
    //   const findSonNodes = [];
    //   this.self.localData.forEach(item => {
    //     if (item?.p_id) {
    //       if (item.p_id === rowID) {
    //         const updateItem = [
    //           new ts.T_fv()
    //             .setField(Tsrv.globalVar.fieldName.ID)
    //             .setValue(item.id),
    //           new ts.T_fv()
    //             .setField(Tsrv.globalVar.fieldName.parentId)
    //             .setValue('')
    //         ];
    //         findSonNodes.push(updateItem);
    //       }
    //     }
    //   });
    //   const changes = {
    //     insertRecords: [],
    //     updateRecords: [],
    //     removeRecords: []
    //   };
    //   if (findSonNodes.length > 0) {
    //     changes.updateRecords.push(...findSonNodes);
    //     tableEditor.doSave(changes).then(r => {
    //       if (r) {
    //         this.self.$emit('on-row-change', 'delete', currentRow);
    //       }
    //     });
    //   }
    // }
  }

  nodeContextMenu = (e: N_cFlowchart.I_eventParams) => {
    this.setCurrEventParams(e);
    // 定位节点
    const node = e.node;
    this.currentNode = node;
    this.currentRow = this.self.localData.find(item => item?.id === node.id);
    const currentRowData = {
      config: this.self.tableCfg,
      ev: {}
    };
    currentRowData.ev['row'] = this.currentRow;
    this.currentRowData = currentRowData;

    // 定位菜单位置
    const p: N_oContextMenu.I_showPosition = {
      clientX: e.e.clientX,
      clientY: e.e.clientY
    };
    this.self.nodeContentMenu(p, e);
  };

  edgeContextMenu = (e: N_cFlowchart.I_eventParams) => {
    this.setCurrEventParams(e);
    const p: N_oContextMenu.I_showPosition = {
      clientX: e.e.clientX,
      clientY: e.e.clientY
    };
    this.self.edgeContentMenu(p, e);
  };

  /**
   * @description: 添加edge连线事件回调
   * @return {*}
   * @author: swc
   * @Date: 2024-08-26 19:47:58
   * @LastEditors: zss
   * @LastEditTime: Do not edit
   */
  edgeAdded = ({ edge, index, options }) => {
    // const graph = this.self.cFlowchart.graph; // node.model.graph
    // // 线不能连接线
  };

  /**
   * @description: 连线————连接事件——> 1、修改节点关系（）——> 2、
   * @description: 重要：——结合edge:remove事件实现（）——> 删除连线则删除两节点间的父子关系
   * @description: 现将修改：不设置父关系，只设置子关系
   * @param {N_cFlowchart} e
   * @return {*}
   * @author: swc
   * @Date: 2024-08-26 19:23:47
   * @LastEditors: swc
   * @LastEditTime: Do not edit
   */
  edgeConnected = (e: N_cFlowchart.I_edgeConnectParams) => {
    const graph = this.self.cFlowchart.graph;
    const edge = e.edge;
    const source = edge.getSourceNode();
    // （建立在连线规则上：1:线不能连接线、2:连线如果没有target，该连线不成立——即：自动删除）
    const target = edge.getTargetNode();
    let connectable = true;
    // e.type —— source, target
    if (e.type === 'target') {
      // const sourceProp = source.getProp();
      // const sourceEdges = graph.getOutgoingEdges(source.id);
      // const targetProp = target.getProp();
      const targetIncomingEdges = graph.getIncomingEdges(target.id);
      const sourceOutgoingEdges = graph.getOutgoingEdges(source.id);
      // 连线规则
      // 规则一：两个节点之间不能相互连接
      const targetOutgoingEdges = graph.getOutgoingEdges(target.id);
      if (!Tsrv.noValue(targetOutgoingEdges)) {
        if (
          targetOutgoingEdges.find(
            item => item.getTargetNode().id === source.id
          )
        ) {
          connectable = false;
          graph.removeEdge(edge.id);
        }
      }
      // 规则二：目标节点不能有多个入边（当前节点允许有多个出点）
      if (targetIncomingEdges.length > 1) {
        connectable = false;
        graph.removeEdge(edge.id);
      }

      // // 规则三：当前节点不能有多个出边
      // if (sourceOutgoingEdges.length > 1) {
      //   connectable = false;
      //   graph.removeEdge(edge.id);
      // }

      // 规则结束执行逻辑
      if (connectable) {
        this.self.$Modal.confirm({
          title: Tsrv.getI18nByValue('连线提醒') as string,
          content: Tsrv.getI18nByValue('是否确定连线') as string,
          onOk: () => {
            this.handleEdgeSuccess(source.id, target.id, false)
              .then(() => {})
              .catch(() => {
                graph.removeEdge(edge.id);
              });
          }
        });
      }
      // 修改的边（现系统不支持）
      // if (!e.isNew) {
      //   // 基于连线规则，该可能性不存在。（避免后期连线规则改变，先做逻辑）
      //   if (e.previousCell) {}
      // }
    } else {
      // source （现系统不支持 倒箭头）
      // 基于连线规则，该可能性不存在。（避免后期连线规则改变，先做逻辑）
      // 新创建的边（应该不存在此可能性：因为edge暂时不存在“倒箭头”的线条）
      if (source) {
        //
      }
      // 修改的边（现系统不支持）
      // if (!e.isNew) {
      //   // 基于连线规则，该可能性不存在。（避免后期连线规则改变，先做逻辑）
      //   if (e.previousCell) {
      //     //
      //   }
      // }
    }
    // graph.removeEdge(edge.id);
  };

  /**
   * @description: 删除边edge事件回调
   * @return {*}
   * @author: swc
   * @Date: 2024-08-26 19:47:58
   * @LastEditors: zss
   * @LastEditTime: Do not edit
   */
  edgeRemoved = ({ edge, index, options }) => {
    // const graph = this.self.cFlowchart.graph;
    // const source = edge.getSourceNode();
    // const target = edge.getTargetNode();
    const sourceId = edge.getProp().source.cell;
    const targetId = edge.getProp().target.cell;
    const localData = this.self._localData;
    const targetRow = localData.find((item: any) => item.id === targetId);
    if (
      !Tsrv.noValue(targetRow) &&
      !Tsrv.noValue(sourceId) &&
      !Tsrv.noValue(targetId)
    ) {
      if (targetRow?.p_id === sourceId) {
        this.handleEdgeSuccess(sourceId, targetId, true)
          .then(() => {})
          .catch(() => {
            // 边删除（row的p_id清除）失败，则撤回画布的边删除
            this.self.cFlowchart.graph.undo();
          });
      }
    }
  };

  /**
   * @description: 删除节点node事件回调
   * @return {*}
   * @author: swc
   * @Date: 2024-08-26 19:47:58
   * @LastEditors: zss
   * @LastEditTime: Do not edit
   */
  nodeRemoved({ node, index, options }) {
    // if (node.hasParent()) {
    //   node.removeFromParent();
    // }
    const currentRow = Tsrv.utils.clone(this.currentRowData.ev?.row, true);
    this.self.$emit('on-row-change', 'delete', currentRow);
  }

  /**
   * @description: 添加节点node事件回调
   * @return {*}
   * @author: swc
   * @Date: 2024-08-26 19:47:58
   * @LastEditors: zss
   * @LastEditTime: Do not edit
   */
  nodeAdded({ node, index, options }) {
    // const graph = this.self.cFlowchart.graph; // node.model.graph
    const nodeProp = node.getProp();
    const data = node.getData();
    const define = {
      overwrite: false, // 是否覆盖
      deep: false, // 是否深度覆盖
      silent: true // 是否静默修改——是否触发 'change:data' 事件和画布重绘
    };
    node.setData(
      // { id: nodeProp.id, nodeID: Tsrv.utils.custUUID(8, 16) },
      define
    );
    // 添加cell（节点/边）校验（——节点是“开始”“结束”唯一——后期替换c-flowchat文件中的addCellValidate——）
    // if (!Tsrv.noValue(data)) {
    //   if (Tsrv.utils.get(data, 'unique', false)) {
    //     if (graph.getNodes().filter(el => el.shape === node.shape).length > 1) {
    //       graph.removeNode(node.id);
    //     }
    //   }
    // }
  }

  blankContextMenu = (e: N_cFlowchart.I_eventParams) => {
    this.setCurrEventParams(e);
    const p: N_oContextMenu.I_showPosition = {
      clientX: e.e.clientX,
      clientY: e.e.clientY
    };
    this.self.blankContentMenu(p, e);
  };

  private setCurrEventParams(e: N_cFlowchart.I_eventParams) {
    this.currEventParams = null;
    if (!Tsrv.noValue(e)) {
      this.currEventParams = e;
    }
  }

  public flowchartContextMenuSelected(
    key: string,
    cmd: N_cFlowchart.I_cFlowCmd
  ) {
    this.self.cFlowchart.hideContextMenu();
    // const k = key.split(':')[0];
    switch (key) {
      case 'add:node:grid-node':
        this.addGridNode();
        break;
      case 'edit:node:grid-node':
        this.self.oBaseGrid.showRowEditor(this.currentRowData.ev);
        break;
      // case 'modify:cell:data':
      //   // this.openNodeEditor();
      //   break;
      case 'copyAdd:cell':
        this.copyAndAddCell();
        break;
      case 'custom:remove':
        this.deleteNode();
        break;
      case 'export:blank:svg':
        this.exportGraph('svg');
        break;
      case 'export:blank:png':
        this.exportGraph('png');
        break;
      case 'export:blank:jpeg':
        this.exportGraph('jpeg');
        break;
      case 'debug:debug':
        this.debug();
        break;
      default:
        break;
    }
  }

  private addNodeAndEdge(shape: string) {
    const targetNodeID = this.addNode(shape);
    if (this.currEventParams.cell.isNode()) {
      this.addEdge(this.currEventParams.node.id, targetNodeID);
      this.self.cFlowchart.layout();
    }
  }

  private addNode(shape: string): string {
    const nodeID = Tsrv.utils.custUUID(16);
    const nodeParams = {
      shape,
      id: nodeID,
      height: 40,
      width: 80
    };
    // 如果当前有选中的节点，则新节点在选中节点右侧
    const targetNode = this.self.cFlowchart.graph
      .getSelectedCells()
      .find(cell => {
        return cell.shape === shape && cell.isNode();
      });
    if (!Tsrv.noValue(targetNode) && !Tsrv.noValue(targetNode['position'])) {
      nodeParams['x'] = targetNode['position']().x + 50;
      nodeParams['y'] = targetNode['position']().y + 50;
    }

    this.self.cFlowchart.addNode(nodeParams);
    return nodeID;
  }

  private addEdge(source: string, target: string) {
    this.self.cFlowchart.addEdge({
      source,
      target
    });
  }

  private addGridNode() {
    // 1、打开弹窗式增加节点
    this.self.oBaseGrid.showRowEditor();
    // this.self.cFlowchart.layout(); // 重新布局
    // 2、直接增加节点
    // const table = this.self.oBaseGrid;
    // table.getInsertInitData().then(data => {
    //   const nodeParams = {
    //     shape: 'grid-node',
    //     id: data.id,
    //     height: 40,
    //     width: 80
    //   };
    //   this.self.cFlowchart.addNode(nodeParams);
    // });
  }

  // 修改（grid-）
  private openNodeEditor() {
    const cell = this.self.cFlowchart.graph.getSelectedCells()[0];
    if (cell.isNode()) {
      // this.self.showNodeModal(cell);
      const cellProp = cell.getProp();
    } else if (cell.isEdge()) {
      //
    }
  }

  // 修改（grid-）
  /**
   * @description: 修改节点或边的自定义数据（应用于业务）
   * @return {*}
   * @author: swc
   * @Date: 2024-08-20 18:19:56
   * @LastEditors: swc
   * @LastEditTime: Do not edit
   */
  public modifyCellData(cellId: string, data: any) {
    const cell = this.self.cFlowchart.graph.getCellById(cellId);
    if (cell.isNode()) {
      const define = {
        overwrite: false, // 是否覆盖
        deep: false, // 是否深度覆盖
        silent: true // 是否静默修改——是否触发 'change:data' 事件和画布重绘
      };
      cell.setData(data, define);
      if (cell.shape === 'bpmn-activity' && !Tsrv.noValue(data?.checker)) {
        const checker = data.checker;
        cell.setAttrByPath(
          'label/text',
          Tsrv.getI18nBySrv(checker.label) ?? Tsrv.getI18nBySrv(checker.value)
        );
      }
    } else if (cell.isEdge()) {
      // this.self.edgeDataModify(cell);
    }
  }

  /**
   * @description: 复制新增cell
   * @return {*}
   * @author: swc
   * @Date: 2024-08-20 18:19:18
   * @LastEditors: swc
   * @LastEditTime: Do not edit
   */
  private copyAndAddCell() {
    // bugger：复制粘贴后，粘贴的节点和边不能选中（多选情况下）
    const cells = this.self.cFlowchart.graph.getSelectedCells();
    if (cells.length > 0) {
      this.self.cFlowchart.graph.copy(cells);
      this.self.cFlowchart.graph.paste({ offset: 20 });
    }
  }

  debug() {
    // const graph = this.self.cFlowchart.graph;
    // const cells = this.self.cFlowchart.graph.getSelectedCells();
  }

  public exportGraph(type: 'jpeg' | 'png' | 'svg') {
    switch (type) {
      case 'svg':
        this.self.cFlowchart.graph.toSVG(
          (dataUri: string) => {
            DataUri.downloadDataUri(dataUri, 'chart.svg');
          },
          {
            preserveDimensions: true,
            // viewBox: '',
            copyStyles: false
            // stylesheet: '',
            // serializeImages: true,
            // beforeSerialize: (that: N_cFlowchart.x6Graph, svg: SVGSVGElement) => {}
          }
        );
        break;
      case 'png':
        this.self.cFlowchart.graph.toPNG(
          (dataUri: string) => {
            DataUri.downloadDataUri(dataUri, 'chart.png');
          },
          {
            copyStyles: false,
            // width: number,
            // height: number,
            // backgroundColor: string,
            padding: {},
            quality: 1
          }
        );
        break;
      case 'jpeg':
        this.self.cFlowchart.graph.toJPEG(
          (dataUri: string) => {
            DataUri.downloadDataUri(dataUri, 'chart.jpeg');
          },
          {
            copyStyles: false,
            // width: number,
            // height: number,
            // backgroundColor: string,
            padding: {},
            quality: 1
          }
        );
        break;
      default:
        break;
    }
  }

  /**
   * @description: 动态调整右鍵菜單的菜單項
   * @param {*} eventParams
   * @return {*}
   * @author: swc
   * @Date: 2024-08-28 16:17:36
   * @LastEditors: zss
   * @LastEditTime: Do not edit
   */
  public handleMenuItems(
    eventParams: N_cFlowchart.I_eventParams
  ): Array<N_oContextMenu.I_menuItem> {
    const cell = eventParams.cell;
    const contentMenuItem: Array<N_oContextMenu.I_menuItem> = [
      ...cellContentMenuItem()
    ];
    if (cell.isNode()) {
      contentMenuItem.unshift(...nodeContentMenuItem());
    }
    if (cell.isEdge()) {
      contentMenuItem.unshift(...edgeContentMenuItem());
    }
    return contentMenuItem;
  }

  public handleBtnPermission() {
    if (
      !Tsrv.noValue(this.self.tableCfg?.permission) &&
      !Tsrv.noValue(this.self.tableCfg?.toolbar)
    ) {
      const toolbarPermission = this.self.tableCfg.permission.find(
        itm => itm?.area === 'toolbar'
      );
      const editBtnPer = toolbarPermission.data['edit'];
      const editBtntoo = this.self.tableCfg?.toolbar['edit'];
      // this.self.cFlowchart.GT_cmd.setBtnState(
      //   'edit',
      //   'disabled',
      //   !(editBtnPer && editBtntoo)
      // );
      this.self.cFlowchart.GT_cmd.setBtnState(
        'edit',
        'isHide',
        !(editBtnPer && editBtntoo)
      );
      this.self.cFlowchart.GT_cmd.setBtnState(
        'cancelEdit',
        'isHide',
        !(editBtnPer && editBtntoo)
      );
    }
  }

  // 连线成功后，修改节点数据（根据业务需求：修改—节点即row修改字段p_id值）
  public handleEdgeSuccess(
    // source: N_cFlowchart.x6Node,
    // target: N_cFlowchart.x6Node,
    sourceId: string,
    targetId: string,
    isDelete: boolean
  ): Promise<any> {
    return new Promise((resolve, reject) => {
      const tableEditor = this.self.oBaseGrid.GT_editor;
      const changes = this.self.oBaseGrid.getChanges();
      const modifyChange: Array<ts.T_fv> = [
        // new ts.T_fv().setField(Tsrv.globalVar.fieldName.ID).setValue(target.id),
        new ts.T_fv().setField(Tsrv.globalVar.fieldName.ID).setValue(targetId),
        new ts.T_fv()
          .setField(Tsrv.globalVar.fieldName.parentId)
          // .setValue(isDelete ? null : source.id)
          .setValue(isDelete ? null : sourceId)
      ];
      changes.updateRecords.push(modifyChange);
      tableEditor
        .doSave(changes)
        .then(() => {
          tableEditor.sendEventCoordination('save');
          tableEditor.unLockALL();
          resolve(true);
        })
        .catch(() => {
          reject();
        });
    });
  }
}
interface I_cmd extends T_cmd {}
export { I_cmd, T_cmd };
